package services

import (
	"context"
	"github.com/golang/protobuf/ptypes/empty"
	"github.com/golang/protobuf/ptypes/wrappers"
	"time"

	"kop/framework/broker"
	context2 "kop/framework/context"
	"kop/libs/database"
	"kop/modules/pay/configuration"
	"kop/modules/pay/entity"
	"kop/modules/pay/models"
	"kop/pb"
	"kop/pb/service"

	roleC "kop/modules/role/client"
)

var Handler *payServiceHandler

func PayServiceHandler() *payServiceHandler {

	if Handler == nil {
		Handler = &payServiceHandler{}
	}
	return Handler
}

type payServiceHandler struct {
	context2.Context
}

func (h *payServiceHandler) GetProducts(ctx context.Context, _ *empty.Empty, resp *pb.Products) error {

	var double, err = models.GetDouble(database.DB, h.GetRoleID(ctx))
	if err != nil {
		return err
	}

	resp.Products = make([]*pb.Product, 0, len(configuration.Configs))

	for _, v := range configuration.Configs {
		resp.Products = append(resp.Products, &pb.Product{
			ProductID:   v.ProductID,
			Price:       v.Price,
			Diamond:     v.Diamond,
			Type:        v.Type,
			ProductCode: v.ProductCode,
			Double:      !double.HaveProduct(v.ProductID),
		})
	}

	return nil
}

func (h *payServiceHandler) Create(ctx context.Context, req *wrappers.Int32Value, resp *wrappers.Int64Value) error {

	var conf, err = configuration.GetByProductID(req.Value)
	if err != nil {
		return err
	}

	var order = entity.Order{
		UserID:    h.GetUserID(ctx),
		ServerID:  h.GetServerID(ctx),
		RoleID:    h.GetRoleID(ctx),
		ProductID: req.Value,
		Price:     int64(conf.Price),
		Diamond:   int64(conf.Diamond),
		State:     entity.StateCreate,
	}

	if err = database.DB.Create(&order).Error; err == nil {
		resp.Value = order.ID
	}

	return err
}

func (h *payServiceHandler) Activity(ctx context.Context, req *wrappers.Int64Value, resp *service.PayActivityResp) error {

	var model entity.Order
	var roleID = h.GetRoleID(ctx)

	var now = time.Now()
	var today = time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)

	var startTime = time.Unix(req.Value, 0)
	database.DB.Model(&model).Select("SUM(diamond) AS daily").Where("role_id = ? AND created_at > ? AND state = 2", roleID, today).Scan(resp)
	database.DB.Model(&model).Select("SUM(diamond) AS total").Where("role_id = ? AND created_at > ? AND  state = 2", roleID, startTime).Scan(resp)
	database.DB.Model(&model).Where("role_id = ? AND created_at > ? AND  state = 2", roleID, startTime).Group("TO_CHAR(created_at, 'YYYY-MM-DD')").Count(&resp.Day)
	return nil
}

func (h *payServiceHandler) CallBack(orderID int) error {

	var order, err = models.GetOrder(database.DB, orderID)
	if err != nil {
		return err
	}

	if order.State != entity.StateCreate {
		return nil
	}

	// 先把订单设置为已到账
	order.State = entity.StateOK
	if err := database.DB.Save(&order).Error; err != nil {
		return err
	}

	go h.callPaySuccess(order)

	return nil
}

func (h *payServiceHandler) Cancel(orderID int64) error {

	var order entity.Order
	if err := database.DB.First(&order, orderID).Error; err != nil {
		return err
	}

	if order.State != entity.StateCreate {
		return nil
	}

	order.State = entity.StateCancel
	return database.DB.Save(&order).Error
}

// 调用角色服务器增加VIP积分与钻石
func (h *payServiceHandler) callPaySuccess(order entity.Order) {

	var double, err = models.GetDouble(database.DB, order.RoleID)
	if err != nil {
		return
	}

	var conf, _ = configuration.GetByProductID(order.ProductID)
	var product = pb.Product{
		ProductID: order.ProductID,
		Price:     int32(order.Price),
		Diamond:   int32(order.Diamond),
		Type:      conf.Type,
	}

	if product.Type == pb.ProductType_Product_Diamond {

		if !double.HaveProduct(order.ProductID) {
			double.SetProduct(order.ProductID)
			database.DB.Save(&double)

			product.Double = true
		}
	}

	if _, err := roleC.RoleService.PaySuccess(context.Background(), &service.PaySuccessRequest{RoleID: order.RoleID, Product: &product}); err == nil {
		// 把订单设置为完成
		order.State = entity.StateComplete
		database.DB.Save(&order)
	}

	_ = broker.RolePublish(order.RoleID, pb.WsCode_PaySuccess, &wrappers.Int32Value{Value: order.ProductID})
}

type Products []*pb.Product

func (c Products) Len() int           { return len(c) }
func (c Products) Swap(i, j int)      { c[i], c[j] = c[j], c[i] }
func (c Products) Less(i, j int) bool { return c[i].ProductID < c[j].ProductID }
